package com.example.zzx.heartanimation

import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PointF
import android.util.AttributeSet
import android.view.View
import android.view.View.MeasureSpec.EXACTLY
import android.view.animation.LinearInterpolator
import androidx.core.content.ContextCompat
import com.example.baselibrary.R

class HeartView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null , defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    val STATE_INITIAL = 0
    val STATE_FINAL = 1
    var currentState = STATE_INITIAL

    var paint: Paint
    var path: Path

    var initialColor = ContextCompat.getColor(context, R.color.color_white)
    var finalColor = ContextCompat.getColor(context, R.color.colorAccent)

    init {
        paint = Paint()
        paint.style = Paint.Style.FILL_AND_STROKE
        paint.isAntiAlias = true
        paint.color = initialColor

        path = Path()
    }

    var totalWidth = 0F
    var totalHeight = 0F

    lateinit var startPoint: PointF
    lateinit var endPoint: PointF

    lateinit var leftPoint1: PointF
    lateinit var leftPoint2: PointF

    lateinit var rightPoint1: PointF
    lateinit var rightPoint2: PointF

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val height = MeasureSpec.getSize(heightMeasureSpec)

        val result = Math.min(width, height)
        super.onMeasure(MeasureSpec.makeMeasureSpec(result, EXACTLY),
                MeasureSpec.makeMeasureSpec(result, EXACTLY))
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        totalWidth = w.toFloat()
        totalHeight = h.toFloat()

        startPoint = PointF(totalWidth / 2F, totalHeight / 8 * 7)
        endPoint = PointF(totalWidth / 2, totalHeight / 4)
        leftPoint1 = PointF(0F, totalHeight / 3 * 2)
        leftPoint2 = PointF(0F, 0F)
        rightPoint1 = PointF(totalWidth, totalHeight / 3 * 2)
        rightPoint2 = PointF(totalWidth, 0F)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        paint.color = if (currentState == STATE_INITIAL) initialColor else finalColor

        path.moveTo(startPoint.x, startPoint.y)
        path.cubicTo(leftPoint1.x, leftPoint1.y, leftPoint2.x, leftPoint2.y, endPoint.x, endPoint.y)

        path.moveTo(startPoint.x, startPoint.y)
        path.cubicTo(rightPoint1.x, rightPoint1.y, rightPoint2.x, rightPoint2.y, endPoint.x, endPoint.y)

        canvas?.drawPath(path, paint)
    }

    fun setColor(initialColor: Int, finalColor: Int) {
        this.initialColor = initialColor
        this.finalColor = finalColor
    }

    private fun likeAnimation() {
        currentState = STATE_FINAL
        postInvalidate()
        val scaleX = ObjectAnimator.ofFloat(this, "scaleX", 0.5F, 1.0F)
        val scaleY = ObjectAnimator.ofFloat(this, "scaleY", 0.5F, 1.0F)
        val animatorSet = AnimatorSet()
        animatorSet.interpolator = BeatingInterpolator
        animatorSet.duration = 1000
        animatorSet.playTogether(scaleX, scaleY)
        animatorSet.start()
    }

    private fun cancelLikeAnimation() {
        currentState = STATE_INITIAL
        postInvalidate()
        val scaleX = ObjectAnimator.ofFloat(this, "scaleX", 0.5F, 1.0F)
        val scaleY = ObjectAnimator.ofFloat(this, "scaleY", 0.5F, 1.0F)
        val animatorSet = AnimatorSet()
        animatorSet.interpolator = BeatingInterpolator
        animatorSet.duration = 1000
        animatorSet.playTogether(scaleX, scaleY)
        animatorSet.start()
    }

    fun toggle() {
        if (currentState == STATE_INITIAL) likeAnimation()
            else cancelLikeAnimation()
    }

    fun initState(state: Int) {
        currentState = if (state == STATE_FINAL) STATE_FINAL else STATE_INITIAL
        postInvalidate()
    }

    object BeatingInterpolator: LinearInterpolator() {

        var factor = 0.15F

        override fun getInterpolation(input: Float): Float {
            return (Math.pow(2.0, (-10 * input).toDouble()) * Math.sin((input - factor / 4)
                    * (2 * Math.PI) / factor) + 1).toFloat()
        }
    }

}